package com.huxi.http;

import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Objects;

import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

public class CloseableClient extends Client {

	private final HttpComponentsClientHttpRequestFactory factory;
	private final CloseableHttpClient httpClient;

	protected CloseableClient(HttpComponentsClientHttpRequestFactory factory, CloseableHttpClient httpClient,
			RestTemplate restTemplate) {
		super(restTemplate);
		this.factory = Objects.requireNonNull(factory);
		this.httpClient = Objects.requireNonNull(httpClient);
	}

	/**
	 * 创建HTTP客户端
	 * 
	 * @param connectTimeout 连接超时（毫秒）
	 * @param readTimeout    读取超时（毫秒）
	 * @return HTTP客户端，非空值。
	 */
	public static CloseableClient of(int connectTimeout, int readTimeout) {
		return of(connectTimeout, readTimeout, null);
	}

	/**
	 * 创建HTTP客户端
	 * 
	 * @param connectTimeout 连接超时（毫秒）
	 * @param readTimeout    读取超时（毫秒）
	 * @param charset        服务响应字符编码（默认UTF8)
	 * @return HTTP客户端，非空值。
	 */
	public static CloseableClient of(int connectTimeout, int readTimeout, Charset charset) {
		CloseableHttpClient httpClient = HttpClients.custom() // 开始定制客户端
				.setKeepAliveStrategy((response, context) -> 30 * 1000) // 保持连接30秒
//				.setMaxConnPerRoute(10) // 单个路由地址连接池最大数量
//				.setMaxConnTotal(100) // 连接池总连接数最大值
				.build();
		return of(httpClient, connectTimeout, readTimeout, charset);
	}

	/**
	 * 创建HTTP客户端
	 * 
	 * @param httpClient     底层客户端，非控制。
	 * @param connectTimeout 连接超时（毫秒）
	 * @param readTimeout    读取超时（毫秒）
	 * @param charset        服务响应字符编码（默认UTF8)
	 * @return HTTP客户端，非空值。
	 */
	public static CloseableClient of(CloseableHttpClient httpClient, int connectTimeout, int readTimeout,
			Charset charset) {
		HttpComponentsClientHttpRequestFactory requestFactory = createClientHttpRequestFactory(httpClient,
				connectTimeout, readTimeout);
		return new CloseableClient(requestFactory, httpClient, createRestTemplate(requestFactory, charset));
	}

	private static HttpComponentsClientHttpRequestFactory createClientHttpRequestFactory(CloseableHttpClient httpClient,
			int connectTimeout, int readTimeout) {
		Objects.requireNonNull(httpClient, "HTTP客户端参数不能为空值");
		HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
		// 设置连接超时时间（单位：毫秒）
		requestFactory.setConnectTimeout(connectTimeout);
		// 设置读取超时时间（单位：毫秒）
		requestFactory.setReadTimeout(readTimeout);
		requestFactory.setHttpClient(httpClient);
		return requestFactory;
	}

	/**
	 * 重置HTTP客户端连接超时
	 * 
	 * @param connectTimeout 连接超时（毫秒）
	 * @param readTimeout    读取超时（毫秒）
	 * @param charset        响应字符编码
	 * @param 返回新的客户端
	 */
	public CloseableClient reset(int connectTimeout, int readTimeout, Charset charset) {
		if (charset == null) {
			charset = StandardCharsets.UTF_8;
		}
		return of(httpClient, connectTimeout, readTimeout, charset);
	}

	/**
	 * 重置HTTP客户端连接超时
	 * 
	 * @param connectTimeout 连接超时（毫秒）
	 * @param readTimeout    读取超时（毫秒）
	 * @param 返回新的客户端
	 */
	public Client reset(int connectTimeout, int readTimeout) {
		return reset(connectTimeout, readTimeout, StandardCharsets.UTF_8);
	}

	/**
	 * 关闭底层活动的HTTP连接，关闭后此客户端不能再使用。
	 * 
	 * @throws IOException 关闭失败
	 */
	public void close() throws IOException {
		this.httpClient.close(); // 连接关闭后无法再使用
	}

	/**
	 * 设置底层连接等待超时，0则不设置超时。
	 * 
	 * @param timeout 等待超时（毫秒）
	 */
	public void setConnectTimeout(int timeout) {
		factory.setConnectTimeout(timeout);
	}

	/**
	 * 设置底层内容读取等待超时，0则不设置超时。
	 * 
	 * @param timeout 等待超时（毫秒）
	 */
	public void setxx(int timeout) {
		factory.setReadTimeout(timeout);
	}
}
